DartVM RawReceivePort
介绍
在 ReceivePort Dart 层实现中,可以看到其内部是基于 RawReceivePort 实现的。RawReceivePort 根据名字可以看出,是涉及 C/C++ 部分的。
RawReceivePort 抽象类
位于接口类位于 sdk/ilb/isolate/isolate.dart,是一个抽象类。
注解翻译
底层的异步消息接收器。
RawReceivePort 是一个底层特性,Zone 不知道 RawReceivePort 的存在。
该类接收一个 handler 参数,handler 总是能够在 Zone.root 下被触发,言外之意,该行为不受 Zone 控制。
该 Port 机制无法暂停。在发出第一个消息之前,handler 必须先注册,handler 注册前发出的消息都会丢失。
类声明
abstract class RawReceivePort {
/// 创建一个长期活跃的接口来接收消息
/// handler 可以在构造时传入,也可以后面通过 setter 传
/// debugName 供调试工具使用
external factory RawReceivePort([Function? handler, String debugName = '']);
/// handler 的 setter
/// 在 Dart 侧传入,默认 Zone.root 上回调,但是可以转 Zone:
/// ```dart
/// rawPort.handler = Zone.current.bind(actualHandler);
/// ```
void set handler(Function? newHandler);
/// 关闭端口
/// 关闭之后,后续收到的消息都丢弃了
void close();
/// 拿到这个 sendPort,就能够向 handler 发送消息
SendPort get sendPort;
}
总结:现在还是疑惑具体的使用场景。更新:解答,在 Dart 侧的 ReceivePort,其内部实现类 _ReceivePortImpl 中,_ReceivePortImpl 的内部创建了 RawReceivePort。也就是说,实际工作都是在 RawReceivePort 中进行的。
构造函数的实现
构造函数的声明和实现是分离的,实现在 sdk/lib/_internal/vm/lib/isolate_patch.dart 中:
@patch
class RawReceivePort {
@patch
factory RawReceivePort([Function? handler, String debugName = '']) {
_RawReceivePortImpl result = new _RawReceivePortImpl(debugName);
result.handler = handler;
return result;
}
}
可以看到,具体的实现在 _RawReceivePortImpl。
_RawReceiverPortImpl
该类位于 sdk/lib/_internal/vm/lib/isolate_patch.dart。
静态全局 _portMap
这是一个全局静态的数据结构,所有 Port 机制的端口,都在这个结构中进行统一维护:
static final _portMap = <int, Map<String, dynamic>>{};
其中:
- key:int 是 Port id
- value:又是一个 Map,通常都只传了一对值 {'port': port},这里的 port 是 _RawReceiverPortImpl 实例。
创建
_RawReceiverPortImpl 构造相关的方法如下:
@pragma("vm:entry-point")
class _RawReceivePortImpl implements RawReceivePort {
factory _RawReceivePortImpl(String debugName) {
final port = _RawReceivePortImpl._(debugName);
_portMap[port._get_id()] = <String, dynamic>{
'port': port,
};
return port;
}
factory _RawReceivePortImpl._(String debugName)
native "RawReceivePortImpl_factory";
/**** Internal implementation details ****/
int _get_id() native "RawReceivePortImpl_get_id";
其中:
- 通过 _RawReceivePortImpl._ 创建 _RawReceivePortImpl 实例(C/C++ 层实际创建)
- 创建出来的 _RawReceivePortImpl 实例放入 _portMap,port 的 id 获取也是在 C 层实现的
接着看 RawReceivePortImpl_factory,来到 runtime/lib/isolate.cc:
DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 2) {
ASSERT(
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
GET_NON_NULL_NATIVE_ARGUMENT(String, debug_name, arguments->NativeArgAt(1));
Dart_Port port_id = PortMap::CreatePort(isolate->message_handler());
return ReceivePort::New(port_id, debug_name, false /* not control port */);
}
其中:
- C层还有一个 PortMap(推测在 C 和 Dart 层两者是对应关系)
- 还要注意传入 PortMap::CreateMap 的 MessageHandler,这里取得是 isolate 的 message_handler
- 这样底层 Port id 未来的唤起,唤醒的是 isolate,而不是 ReceivePort 上层传得 handler(stream.add)
- 那 isolate 的 message_handler 里,必然有一个消息分发的过程:查询 Dart 侧的 PortMap,找到 Dart 的 receivePort,然后调用其 handler。
- 最后一个 return,把 C 层创建的 ReceivePort 实例又抛会到了 Dart 层,与 _RawReceivePortImpl 关联
关于 C 层的 ReceivePort,参见 DartVM ReceivePort。
Handler setter
该类中还有一个 handler setter 方法:
void set handler(Function? value) {
final int id = this._get_id();
if (!_portMap.containsKey(id)) {
_portMap[id] = <String, dynamic>{
'port': this,
};
}
_portMap[id]!['handler'] = value;
}
可以看到,将传入的方法引用,如何添加到 _portMap 结构上。 这段代码实际使用场景是什么样的?在 Dart 侧的 _ReceivePortImpl,在其构造方法中有调用这个 setter:
_ReceivePortImpl.fromRawReceivePort(this._rawPort)
: _controller = new StreamController(sync: true) {
_controller.onCancel = close;
_rawPort.handler = _controller.add;
}
双层 Handler 通信
从这里可以意识到,Dart 层跟 Native 层各有一套 ReceivePort 和 Handler 处理机制。一个套路在 Dart 层和 C/C++ 层使用了两遍。
我凭感觉梳理了一个示意图,可能还不太对:
因为向 Native 的 ReceivePort 传入的 handler 是 Isolate 的 message_handler。